package cn.wp.ewallet.wmps.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.wp.common.core.authentication.AuthenticationContext;
import cn.wp.common.core.dto.WpResult;
import cn.wp.common.core.id.Id;
import cn.wp.common.core.model.WpPage;
import cn.wp.common.core.util.BeanUtil;
import cn.wp.ewallet.common.model.dto.DocContentDto;
import cn.wp.ewallet.common.model.dto.MoneyTypeInfoDto;
import cn.wp.ewallet.common.model.entity.DocContentDo;
import cn.wp.ewallet.common.service.DocContentService;
import cn.wp.ewallet.common.service.MoneyTypeInfoService;
import cn.wp.ewallet.wallet.dao.AccountInfoDao;
import cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant;
import cn.wp.ewallet.wallet.extension.util.EwalletWalletUtil;
import cn.wp.ewallet.wallet.model.dto.UserWalletRelDto;
import cn.wp.ewallet.wallet.model.entity.AccountInfoDo;
import cn.wp.ewallet.wallet.model.entity.AccountInfoDoo;
import cn.wp.ewallet.wallet.service.AccountInfoService;
import cn.wp.ewallet.wallet.service.UserWalletRelService;
import cn.wp.ewallet.wmps.dao.*;
import cn.wp.ewallet.wmps.extension.constant.EwalletWmpsConstant;
import cn.wp.ewallet.wmps.model.dto.FinaProdCountDto;
import cn.wp.ewallet.wmps.model.dto.FinaParmDto;
import cn.wp.ewallet.wmps.model.dto.FinaProdAddressDto;
import cn.wp.ewallet.wmps.model.dto.FinaProdInfoDto;
import cn.wp.ewallet.wmps.model.dto.PurchasedProdOrderRelDto;
import cn.wp.ewallet.wmps.model.entity.*;
import cn.wp.ewallet.wmps.service.FinaProdInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

import static cn.wp.ewallet.wallet.extension.constant.EwalletWalletConstant.*;

/**
 * Created by yangjin on 2020/1/7 12:02
 */
@Service
public class FinaProdInfoServiceImpl implements FinaProdInfoService {

    @Autowired
    private FinaProdInfoDao finaProdInfoDao;

    @Autowired
    private DocContentService docContentService;

    @Autowired
    private AuthenticationContext authenticationContext;

    @Autowired
    private AccountInfoDao accountInfoDao;

    @Autowired
    private AccountInfoService accountInfoService;

    @Autowired
    private ProdOrderRelDao prodOrderRelDao;

    @Autowired
    private FixFinaProdInfoDao fixFinaProdInfoDao;

    @Autowired
    private UserWalletRelService userWalletRelService;

    @Autowired
    private MoneyTypeInfoService moneyTypeInfoService;

    @Autowired
    private EarnStatLogDao earnStatLogDao;
    
    @Autowired
    private ReturnYieldInfoDao returnYieldInfoDao;


    @Override
    public WpPage<FinaProdInfoDto> getFinaProdInfoList(String finaProdName, WpPage page, String status) {
        WpPage<FinaProdInfoDoo> wpPage = null;
        if ("all".equals(status)) {
            wpPage = finaProdInfoDao.selectAllFinaProdInfoList(finaProdName, page);
        }
        if ("upper".equals(status)) {
            wpPage = finaProdInfoDao.selectUpperFindProdInfoList(page);
        }

        return wpPage.doConvertDto(FinaProdInfoDto.class);

    }

    @Override
    public void saveFinaProdInfo(FinaProdInfoDto finaProdInfoDto) {
        //保存理财产品
        FinaProdInfoDo finaProdInfoDo = saveFinaProdInfoDo(finaProdInfoDto);
        //保存定期理财产品
        FixFinaProdInfoDo fixFinaProdInfoDo = BeanUtil.copyProperties(finaProdInfoDto, FixFinaProdInfoDo.class);
        fixFinaProdInfoDo.setFinaProdId(finaProdInfoDo.getFinaProdId());
        fixFinaProdInfoDao.insertFixFinaProdInfo(fixFinaProdInfoDo);
    }

    @Override
    public Boolean modifyFinaProdInfo(FinaProdInfoDto finaProdInfoDto) {
        FixFinaProdInfoDo finaProdCountDo = fixFinaProdInfoDao.selectfixFinaProdInfo(finaProdInfoDto.getFinaProdId());
        if (null == finaProdCountDo) {
            //产品不存在
            return false;
        }

        //更新理财产品信息
        FinaProdInfoDo finaProdInfoDo = BeanUtil.copyProperties(finaProdInfoDto, FinaProdInfoDo.class);
        finaProdInfoDo.setUpdateDate(new Date());
        finaProdInfoDo.setUpdateUser(authenticationContext.currentUser().getId());
        finaProdInfoDao.updateFindProdInfo(finaProdInfoDo);
        //更新定期理财产品信息
        FixFinaProdInfoDo fixFinaProdInfoDo = BeanUtil.copyProperties(finaProdInfoDto, FixFinaProdInfoDo.class);
        fixFinaProdInfoDao.updateFixFinaProdInfo(fixFinaProdInfoDo);

        return true;
    }

    private FinaProdInfoDo saveFinaProdInfoDo(FinaProdInfoDto finaProdInfoDto) {
        FinaProdInfoDo finaProdInfoDo = BeanUtil.copyProperties(finaProdInfoDto, FinaProdInfoDo.class);
        finaProdInfoDo.setFinaProdId(Id.gen());
        finaProdInfoDo.setProdType(EwalletWmpsConstant.PROD_TYPE_REGULAR);
        finaProdInfoDo.setReturnRateCycle(EwalletWmpsConstant.RETURN_RATE_CYCLE_QUARTER);
        finaProdInfoDo.setStatus(EwalletWmpsConstant.FINA_PROD_STATUS_STAY_ON);
        finaProdInfoDo.setStatusDate(new Date());
        finaProdInfoDo.setCreateDate(new Date());
        finaProdInfoDo.setCreateUser(authenticationContext.currentUser().getId());
        finaProdInfoDao.insertFinaProdInfo(finaProdInfoDo);
        return finaProdInfoDo;
    }

    @Override
    public void upperFinaProdInfo(String finaProdId) {
        finaProdInfoDao.updateFindProdInfoById(finaProdId);
    }

    @Override
    public void lowerFinaProdInfo(String finaProdId) {
        finaProdInfoDao.updateFindProdInfoById2(finaProdId);
    }

    @Override
    public WpResult getFinaProdInfoRole(String finaProdId, String langCode) {
        List<DocContentDo> docContentDos = docContentService.getFinaProdInfoRoleByfinaProdId(finaProdId, langCode);
        List<DocContentDto> docContentDtos = BeanUtil.listCopyProperties(docContentDos, DocContentDto.class);
        return new WpResult().success(docContentDtos);
    }

    @Override
    public Map getFixFinaAmountInfo() {
        UserWalletRelDto userWalletRel = userWalletRelService.getUserWalletRel();
        String address = userWalletRel.getWalletAddress();
        String yesterDay = DateUtil.formatDate(DateUtil.offsetDay(new Date(), -1));
        EarnStatLogDo earnStatLogDo = earnStatLogDao.selectEarnStatLogByDate(address, yesterDay);

        //获取SHQC数据精度
        MoneyTypeInfoDto moneyTypeInfoDto = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_SHQC);
        BigDecimal shqcUnit = BigDecimal.valueOf(Long.valueOf(moneyTypeInfoDto.getMoneyTypeUnit()));

        Map map = new HashMap<>();

        if (null != earnStatLogDo) {
            BigDecimal sumWaitReturnYeld = earnStatLogDo.getReturnEarn();//待返还
            BigDecimal sumAlreadyReturnYeld = earnStatLogDo.getFinaTotalEarn();//已返
            map.put("sumAlreadyReturnYeld", EwalletWalletUtil.toUpperWei(sumAlreadyReturnYeld, shqcUnit)); //已返金额
            map.put("sumWaitReturnYeld", EwalletWalletUtil.toUpperWei(sumWaitReturnYeld, shqcUnit));//待返金额
        }
        AccountInfoDo accountInfoDo = accountInfoDao.selectAccountByWalletAddAccountType(address, EwalletWmpsConstant.ACCOUNT_TYPE_FINA);

        BigDecimal allPurchasedYeld = prodOrderRelDao.selectSumPurchaseYeldByAccountAndType(accountInfoDo.getAccountId(), EwalletWmpsConstant.PROD_TYPE_REGULAR);

        map.put("allPurchasedYeld", EwalletWalletUtil.toUpperWei(allPurchasedYeld, shqcUnit));//总金额
        return map;
    }

    @Override
    public List<PurchasedProdOrderRelDto> getFixFinaInfo(String orderStatus1, String orderStatus2) {

        UserWalletRelDto userWalletRel = userWalletRelService.getUserWalletRel();
        String address = userWalletRel.getWalletAddress();
        AccountInfoDo accountInfoDo = accountInfoDao.selectAccountByWalletAddAccountType(address, EwalletWmpsConstant.ACCOUNT_TYPE_FINA);

        //获取SHQC数据精度
        MoneyTypeInfoDto moneyTypeInfoDto = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(MONEY_TYPE_SHQC);
        BigDecimal shqcUnit = BigDecimal.valueOf(Long.valueOf(moneyTypeInfoDto.getMoneyTypeUnit()));

        List<PurchasedProdOrderRelDto> purchasedProdOrderRelDtos = new ArrayList<>();
        //查看持有的定期理财产品
        List<PurchasedProdOrderRelDoo> purchasedProdOrderRelDoos = finaProdInfoDao.selectFixfinaProdInfo(accountInfoDo.getAccountId(), orderStatus1, orderStatus2);
        for (PurchasedProdOrderRelDoo purchasedProdOrderRelDoo : purchasedProdOrderRelDoos) {
            //理财持有额度精度转换
            if (null != purchasedProdOrderRelDoo.getPurchAmount()) {
                purchasedProdOrderRelDoo.setPurchAmount(EwalletWalletUtil.toUpperWei(purchasedProdOrderRelDoo.getPurchAmount(), shqcUnit));
            }
            //理财收益精度转换
            if (null != purchasedProdOrderRelDoo.getEarnAmount()) {
                purchasedProdOrderRelDoo.setEarnAmount(EwalletWalletUtil.toUpperWei(purchasedProdOrderRelDoo.getEarnAmount(), shqcUnit));
            }
            PurchasedProdOrderRelDto purchasedProdOrderRelDto = BeanUtil.copyProperties(purchasedProdOrderRelDoo, PurchasedProdOrderRelDto.class);
            Date date = new Date();
            if (date.getTime() > purchasedProdOrderRelDoo.getEffDate().getTime()) {
                purchasedProdOrderRelDto.setLaveDays(differentDays(date, purchasedProdOrderRelDoo.getExpTime()));
            }
            purchasedProdOrderRelDtos.add(purchasedProdOrderRelDto);
        }
        return purchasedProdOrderRelDtos;
    }

    @Override
    public WpPage<FinaProdAddressDto> getFinaProdInfoListByParam(FinaParmDto finaParmDto, WpPage wpPage) {
        WpPage<FinaProdAddressDoo> finaProdAddressDooWpPage = finaProdInfoDao.selectFinaProdInfoListByParam(finaParmDto, wpPage);
        MoneyTypeInfoDto moneyTypeInfoDto = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(EwalletWalletConstant.MONEY_TYPE_SHQC);
        return finaProdAddressDooWpPage.doConvertDto(FinaProdAddressDto.class, new BeanUtil.Processor<FinaProdAddressDoo, FinaProdAddressDto>() {
            @Override
            public void convert(FinaProdAddressDoo source, FinaProdAddressDto target) {
                if (null == source.getPurchAmount()) {
                    target.setPurchAmount(BigDecimal.ZERO);
                } else {
                    target.setPurchAmount(EwalletWalletUtil.toUpperWei(source.getPurchAmount(), new BigDecimal(moneyTypeInfoDto.getMoneyTypeUnit())));
                }
                target.setPurchTime(DateUtil.formatDateTime(source.getPurchTime()));
                target.setExpTime(DateUtil.formatDate(source.getExpTime()));
            }
        });
    }


    /**
     * 查询所有定期理财产品  各自购买人数、各自总的购买金额
     *
     * @return
     */
    @Override
    public WpPage<FinaProdCountDto> getFixFinaProdCountDtoList(WpPage wpPage) {
        FinaProdInfoDo finaProdInfoDo = finaProdInfoDao.selectTtyParams();
//       天天盈的理财产品id
        String finaProdIdTTy = finaProdInfoDo.getFinaProdId();
        WpPage<FinaProdCountDoo> finaProdCountDooPage = finaProdInfoDao.getFinaProdCountDoos(finaProdIdTTy, wpPage);
        MoneyTypeInfoDto moneyTypeInfoDto = moneyTypeInfoService.getMoneyTypeInfoByMoneyTypeId(EwalletWalletConstant.MONEY_TYPE_SHQC);
        return finaProdCountDooPage.doConvertDto(FinaProdCountDto.class, new BeanUtil.Processor<FinaProdCountDoo, FinaProdCountDto>() {
            @Override
            public void convert(FinaProdCountDoo source, FinaProdCountDto target) {
                if (null == source.getFinaProdCountMoney() || "".equals(source.getFinaProdCountMoney())) {
                    target.setFinaProdCountMoney(BigDecimal.ZERO);
                } else {
                    target.setFinaProdCountMoney(EwalletWalletUtil.toUpperWei(source.getFinaProdCountMoney(), new BigDecimal(moneyTypeInfoDto.getMoneyTypeUnit())));
                }
            }
        });
    }

    /**
     * 查询不同种类的定期理财产品占 总定期理财销售额的比例
     *
     * @return
     */
    @Override
    public WpResult getgetFixFinaProdCountPercent() {
        FinaProdInfoDo finaProdInfoDo = finaProdInfoDao.selectTtyParams();
//       天天盈的理财产品id
        String finaProdIdTTy = finaProdInfoDo.getFinaProdId();
        List<FinaProdCountDoo> finaProdCountDooList = finaProdInfoDao.getFinaProdCountDooByLicai(finaProdIdTTy);
        return new WpResult().success(countPercentage(finaProdCountDooList));
    }

    /**
     * 由SHQC转出----> 到天天盈产品
     *
     * @param
     * @return
     */
    @Transactional
    @Override
    public WpResult turnInTianTianYingOrder(BigDecimal turnInMoney) {

        //用户钱包地址
        UserWalletRelDto userWalletRelDto = userWalletRelService.getUserWalletRel();
        String walletAdd = userWalletRelDto.getWalletAddress();
        //获取SHQC的账户信息
        AccountInfoDoo shqcAccount = accountInfoDao.selectAccountByWalletAddMoneyTypeId(walletAdd, MONEY_TYPE_SHQC, ACCOUNT_TYPE_AVAILABLE);
        //获取 该地址对应的SHQC的账号id,
        AccountInfoDoo shqcTtyAccount = accountInfoDao.selectAccountByWalletAddMoneyTypeId(walletAdd, MONEY_TYPE_SHQC, ACCOUNT_TYPE_CURRENT);
        //购买金额
        BigDecimal purchAmonut = EwalletWalletUtil.toLowerWei(turnInMoney, new BigDecimal(shqcAccount.getMoneyTypeUnit()));
        if (shqcAccount.getMoneyAmount().compareTo(purchAmonut) == -1) {
            return new WpResult().failure(CHECK_AMOUNT_FAILED_CODE, "账户余额不足");
        } else {
            //保存可用资产账户变动信息
            accountInfoService.saveAccountChange(shqcAccount.getWalletAddress(), purchAmonut, ACCOUNT_SUBTRACT, ACCOUNT_CHARGE_CASE_OTHERS, MONEY_TYPE_SHQC, ACCOUNT_TYPE_AVAILABLE);

            //查询天天盈理财产品id
            FinaProdInfoDo finaProdInfoDo = finaProdInfoDao.selectFinaProdInfoByProcType(PRODUCT_TYPE_CURRENT).get(0);
            String finaProdid = finaProdInfoDo.getFinaProdId();
            //新增理财购买记录
            ProdOrderRelDo prodOrderRelDo = new ProdOrderRelDo(Id.gen(), finaProdid, shqcTtyAccount.getAccountId(), purchAmonut, new DateTime(), getEffDate(), COUNT_MONEY_STATUS_BE_CALCULATED, new Date());
            prodOrderRelDao.insertProdOrderRel(prodOrderRelDo);

            //保存天天账户资产账户变动信息
            accountInfoService.saveAccountChange(shqcAccount.getWalletAddress(), purchAmonut, ACCOUNT_ADD, ACCOUNT_CHARGE_CASE_OTHERS, MONEY_TYPE_SHQC, ACCOUNT_TYPE_CURRENT);
            return new WpResult().success(true);
        }
    }

    /**
     * 由天天盈产品转出到 SHQC账户
     *
     * @param turnMoneyOut
     * @return
     */
    @Transactional
    @Override
    public WpResult turnOutTianTianYingOrder(BigDecimal turnMoneyOut) {
        //用户钱包地址
        UserWalletRelDto userWalletRelDto = userWalletRelService.getUserWalletRel();
        String walletAdd = userWalletRelDto.getWalletAddress();
        //天天盈可以支配的余额
        AccountInfoDoo accountInfoDoo = accountInfoDao.selectAccountByWalletAddMoneyTypeId(walletAdd, MONEY_TYPE_SHQC, ACCOUNT_TYPE_CURRENT);
        //转出money
        BigDecimal turnOutMoney = EwalletWalletUtil.toLowerWei(turnMoneyOut, new BigDecimal(accountInfoDoo.getMoneyTypeUnit()));
        //天天盈账户的余额和 要转出的金额对比下
        if (accountInfoDoo.getMoneyAmount().compareTo(turnOutMoney) == -1) {
            return new WpResult().success(CHECK_AMOUNT_FAILED_CODE, "账户余额不足");
        } else {

            //保存天天账户资产账户变动信息
            accountInfoService.saveAccountChange(accountInfoDoo.getWalletAddress(), turnOutMoney, ACCOUNT_SUBTRACT, ACCOUNT_CHARGE_CASE_FINANCIAL_INCOME, MONEY_TYPE_SHQC, ACCOUNT_TYPE_CURRENT);

            //保存可用资产账户变动信息
            accountInfoService.saveAccountChange(accountInfoDoo.getWalletAddress(), turnOutMoney, ACCOUNT_ADD, ACCOUNT_CHARGE_CASE_FINANCIAL_INCOME, MONEY_TYPE_SHQC, ACCOUNT_TYPE_AVAILABLE);

            return new WpResult().success(true);
        }
    }

    @Override
    public void modifyYieldRate(BigDecimal yieldRate, String finaProdDesc) {
        List<FinaProdInfoDo> finaProdInfoDos = finaProdInfoDao.selectFinaProdInfoByProcType(EwalletWmpsConstant.PROD_TYPE_DAILY);
        FinaProdInfoDo finaProdInfoDo = finaProdInfoDos.get(0);
        finaProdInfoDo.setYieldRate(yieldRate.divide(new BigDecimal(100)));
        finaProdInfoDo.setFinaProdDesc(finaProdDesc);
        finaProdInfoDao.updateFindProdInfo(finaProdInfoDo);


    }

    @Override
    public WpResult getTtyParams() {
        FinaProdInfoDo finaProdInfoDo = finaProdInfoDao.selectTtyParams();
        return new WpResult().success(BeanUtil.copyProperties(finaProdInfoDo, FinaProdInfoDto.class));
    }

    /**
     * 获取 天天盈的生效时间
     *
     * @return
     */
    public Date getEffDate() {
        Date now = new Date();
        int hour = now.getHours();
        int min = now.getMinutes();
        int second = now.getSeconds();
        LocalDate localDate = null;
        ZonedDateTime zonedDateTime = null;
        Date effDate = null;
        //当天15点之前，生效时间+1
        if (hour < 15 || (hour == 15 && min == 0 && second == 0)) {
            localDate = LocalDate.now().plusDays(1);
            zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
            Instant instant1 = zonedDateTime.toInstant();
            effDate = Date.from(instant1);
            //当天15点之后，生效时间+2
        } else {
            localDate = LocalDate.now().plusDays(2);
            zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
            Instant instant1 = zonedDateTime.toInstant();
            effDate = Date.from(instant1);
        }
        return effDate;
    }


    public long differentDays(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        int day1 = cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);

        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if (year1 != year2)   //不同一年
        {
            int timeDistance = 0;
            for (int i = year1; i < year2; i++) {
                if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)    //闰年
                {
                    timeDistance += 366;
                } else    //不是闰年
                {
                    timeDistance += 365;
                }
            }
            return timeDistance + (day2 - day1);
        } else {
            return day2 - day1;
        }
    }

    public int updateAccountInfoMoney(String walletAdd, String accountType, BigDecimal afterUpdate, String
            moneyTypeId) {
        AccountInfoDoo dayDayYingAccountInfo = new AccountInfoDoo();
        dayDayYingAccountInfo.setWalletAddress(walletAdd);
        dayDayYingAccountInfo.setAccountType(accountType);
        dayDayYingAccountInfo.setMoneyAmount(afterUpdate);
        dayDayYingAccountInfo.setMoneyTypeId(moneyTypeId);
        //更新天天盈 的余额
        return accountInfoDao.updateAccountInfo(dayDayYingAccountInfo);
    }


    /**
     * 计算 百分比 不同理财产品购买总金额 占总金额的的百分比
     *
     * @param list
     * @return
     */
    public List<FinaProdCountDto> countPercentage(List<FinaProdCountDoo> list) {
        if (list.isEmpty()) {
            return null;
        }
        List<FinaProdCountDto> listDto = new ArrayList<>();
        BigDecimal sumCountMoney = new BigDecimal("0");
        for (int i = 0; i < list.size(); i++) {
            FinaProdCountDoo finaProdCountDoo = list.get(i);
            BigDecimal finaProdCountMoney = finaProdCountDoo.getFinaProdCountMoney();
            if (null == finaProdCountMoney) {
                sumCountMoney = sumCountMoney.add(BigDecimal.ZERO);
                finaProdCountDoo.setFinaProdCountMoney(BigDecimal.ZERO);
            } else {
                sumCountMoney = sumCountMoney.add(finaProdCountMoney);
            }
        }
        for (int i = 0; i < list.size(); i++) {
            FinaProdCountDoo finaProdCountDoo = list.get(i);
            FinaProdCountDto finaProdCountDto = BeanUtil.copyProperties(finaProdCountDoo, FinaProdCountDto.class);
            BigDecimal finaProdCountMoney = finaProdCountDto.getFinaProdCountMoney();
            if (null == finaProdCountMoney || finaProdCountMoney.compareTo(BigDecimal.ZERO) < 1) {
                finaProdCountDto.setFinaProdCountMoneyPercentage(BigDecimal.ZERO);
            } else if (sumCountMoney == null) {
                finaProdCountDto.setFinaProdCountMoneyPercentage(BigDecimal.ZERO);
            } else {
                BigDecimal percentAge = finaProdCountMoney.divide(sumCountMoney, 4, BigDecimal.ROUND_CEILING);
                finaProdCountDto.setFinaProdCountMoneyPercentage(percentAge);
            }
            listDto.add(finaProdCountDto);
        }
        return listDto;
    }
}

